package yjj.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import yjj.exception.BusinessException;
import yjj.model.web.Result;


import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 全局异常处理器，用于统一处理应用中的异常
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;
    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    // 专门处理 AuthenticationException
    @ExceptionHandler(AuthenticationException.class)
    public void handleInsufficientAuthenticationException(HttpServletRequest request, HttpServletResponse response, InsufficientAuthenticationException ex) throws IOException, ServletException {
        authenticationEntryPoint.commence(request, response, ex);
    }
    // 专门处理 AccessDeniedException
    @ExceptionHandler(AccessDeniedException.class)
    public void handleAccessDeniedException(HttpServletRequest request, HttpServletResponse response, AccessDeniedException ex) throws IOException, ServletException {
        accessDeniedHandler.handle(request, response, ex);
    }
    /**
     * 处理自定义的业务异常
     *
     * @param ex BusinessException
     * @return 统一的错误响应
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Result<?>> handleBusinessException(BusinessException ex) {
        Result<?> result = Result.error(ex.getMessage());
        // 根据业务需要设置 HTTP 状态码，这里使用 400 Bad Request 作为示例
        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    }
    /**
     * 处理所有未被捕获的异常
     *
     * @param ex Exception
     * @return 统一的错误响应
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<Result<?>> handleException(Exception ex) {
        // 可以记录日志，方便排查问题
        log.error("异常", ex);

        Result<?> result = Result.error("内部服务器错误");
        // 设置 HTTP 状态码为 500 Internal Server Error
        return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * 处理空指针异常
     *
     * @param ex NullPointerException
     * @return 统一的错误响应
     */
    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<Result<?>> handleNullPointerException(NullPointerException ex) {
       log.error("空指针异常", ex.getMessage());
        Result<?> result = Result.error("空指针异常");
        return new ResponseEntity<>(result, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * 处理非法参数异常
     *
     * @param ex IllegalArgumentException
     * @return 统一的错误响应
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Result<?>> handleIllegalArgumentException(IllegalArgumentException ex) {
        log.error("非法参数", ex.getMessage());
        Result<?> result = Result.error("非法参数: " + ex.getMessage());
        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    }

    /**
     * 处理 @Valid 校验异常
     * @param ex  类型MethodArgumentNotValidException
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Result<?>> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
       // BindingResult bindingResult = exception.getBindingResult();
       // List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        Map<String, String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .collect(Collectors.toMap(
                        FieldError::getField,
                        FieldError::getDefaultMessage,
                        (existing, replacement) -> existing  // 处理相同字段的重复错误
                ));
        /*BinaryOperator扩展了java.util.function.BiFunction。它接受两个相同类型的操作数并对其进行处理，然后返回与操作数相同类型的结果。*/
        log.error("参数验证失败:{}", errors);
        /*List<String> errorMessages = ex.getBindingResult().getAllErrors().stream()
                                    .map(error -> error.getDefaultMessage())
                                    .collect(Collectors.toList());
        StringBuffer stringBuffer = new StringBuffer();
        errorMessages.forEach(error -> stringBuffer.append(error).append(","));
        Result<?> result = Result.error(stringBuffer.toString());*/
        // 收集所有错误消息，并用逗号分隔
        String errorMessage = ex.getBindingResult()
                .getAllErrors()
                .stream()
                .map(ObjectError::getDefaultMessage)
                .collect(Collectors.joining(","));
        // 创建错误结果对象
        Result<?> result = Result.error(errorMessage);
        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    }

    // 你可以根据需要添加更多的异常处理方法
}

